#include "Error.h"
#include "trend.h"

#include <stdio.h>
#include <stdlib.h>

static void trend_recalc_min_up (TrendingList list)
{
	int i;
	TrendingElement min;
	
	min = list->up_list[0];

	for (i = 1; i < 5; i++)
		if (list->up_list[i]->delta_freq > min->delta_freq)
			min = list->up_list[i];

	list->min_up = min;
}

static void trend_recalc_max_down (TrendingList list)
{
	int i;
	TrendingElement max;

	max = list->down_list[0];

	for (i = 1; i < 5; i++)
		if (list->down_list[i]->delta_freq < max->delta_freq)
			max = list->down_list[i];

	list->max_down = max;
}

TrendingElement trend_create_elmt (int delta, char *key)
{
	TrendingElement e;

	if ((e = (TrendingElement) malloc (sizeof (struct _trend_elmt))) == NULL)
		Die ("Failed to allocate space for trending item\n");

	e->delta_freq = delta;
	e->key = key;

	return e;
}

TrendingList trend_init (void)
{
	TrendingList list;

	if ((list = (TrendingList) malloc (sizeof (struct _trend_list))) == NULL)
		Die ("Failed to allocate space for trending list\n");

	list->down_count = 0;
	list->up_count = 0;

	list->max_down = NULL;
	list->min_up = NULL;

	return list;
}

void trend_free (TrendingList *list_t)
{
	int i;
	TrendingList list;
	
	list = *list_t;

	/* Free up list */
	for (i = 0; i < list->up_count; i++)
		free (list->up_list[i]);

	/* Free down list */
	for (i = 0; i < list->down_count; i++)
		free (list->down_list[i]);

	free (list);
}

void trend_insert (TrendingList list, int delta, char *key)
{
	/*delta *= -1;*/

	/* The lists are populated until filled with five elements,
	 * then we start performing comparisons. */

	/* Trending up */
	if (list->up_count < 5 && delta < 0) {
		list->up_list[list->up_count++] = trend_create_elmt (delta, key);
		if (list->up_count == 5)
			trend_recalc_min_up (list);
	} else {
		if (delta < 0 && list->min_up->delta_freq > delta) {
			list->min_up->delta_freq = delta;
			list->min_up->key = key;
			/* Recalculate the minimum for future comparisons */
			trend_recalc_min_up (list);
		}
	}

	/* Trending down */
	if (list->down_count < 5 && delta > 0) {
		list->down_list[list->down_count++] = trend_create_elmt (delta, key);
		if (list->down_count == 5)
			trend_recalc_max_down (list);
	} else {
		if (delta > 0 && list->max_down->delta_freq < delta) {
			list->max_down->delta_freq = delta;
			list->max_down->key = key;
			trend_recalc_max_down (list);
		}
	}
}

void trend_print_lists (TrendingList list) {
	int i, j;
	TrendingElement e;

	/* Sort the lists using horribly inefficient bubble sort ...
	 * but n = 5 so no big deal. */

	for (i = 0; i != list->up_count; i++) {
		for (j = i; j != list->up_count; j++) {
			if ((list->up_list[i]->delta_freq) > (list->up_list[j]->delta_freq)) {
				e = list->up_list[i];
				list->up_list[i] = list->up_list[j];
				list->up_list[j] = e;
			}
		}
	}

	for (i = 0; i != list->down_count; i++) {
		for (j = i; j != list->down_count; j++) {
			if ((list->down_list[i]->delta_freq) < (list->down_list[j]->delta_freq)) {
				e = list->down_list[i];
				list->down_list[i] = list->down_list[j];
				list->down_list[j] = e;
			}
		}
	}
	
	printf ("Trending Up:\n");
	for (i = 0; i < list->up_count; i++) {
		e = list->up_list[i];
		if (e == NULL)
			break;
		printf ("%s (+%d)\n", e->key, (-1*e->delta_freq));
	}

	printf ("\nTrending Down:\n");
	for (i = 0; i < list->down_count; i++) {
		e = list->down_list[i];
		if (e == NULL)
			break;
		printf ("%s (-%d)\n", e->key, e->delta_freq);
	}
}
